<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>legged wheel robot web ctrl</title>
  <style>
    *{box-sizing:border-box;margin:0;padding:0}
    body{display:flex;flex-direction:column;align-items:center;min-height:100vh;background-color:#fff;font-family:'Segoe UI',Arial,sans-serif;padding:15px;overflow:hidden;width:100vw}
    .page-title{color:#333;margin-bottom:15px;text-align:center;font-weight:600;font-size:1.3rem;width:100%}
    .connection-status{margin-bottom:15px;padding:6px 12px;border-radius:4px;font-weight:500;font-size:14px}
    .status-connected{background-color:#e8f5e9;color:#2e7d32}
    .status-disconnected{background-color:#ffebee;color:#c62828}
    .btn{display:inline-block;font-size:15px;width:100px;height:60px;text-align:center;border-radius:12px;background-color:#fff;color:#6495ed;border:3px solid #6495ed;padding:0;transition:all .3s;margin:10px 0}
    .row{display:flex;width:100%;justify-content:space-between;align-items:center;gap:10px}
    .columnLateral{flex:1;min-width:0;text-align:center}
    #joy1Div,#joy2Div{width:100%;max-width:200px;height:200px;margin:10px auto}
    @media (max-width:360px){.page-title{font-size:1.1rem}
    #joy1Div,#joy2Div{height:160px}
    .btn{width:80px;height:50px;font-size:14px}
    }
  </style>
</head>

<!-- onload 事件在页面载入完成后立即触发 -->
<body onload="javascript:socket_init()">
    <h1 class="page-title">WLROBOT WiFi遥控模式</h1>

    <div class="connection-status status-disconnected" id="connectionStatus">未连接</div>

    <center>
        <div class="row">
            <div class="columnLateral">
                 <div id="joy2Div" style="width:200px;height:200px;margin:10px"></div>
                <div id="joy2Info">
                    <span>高度: <span id="joy2YValue">30</span></span>
                    <br>
                    <span>倾角: <span id="joy2XValue">0</span></span>  
                </div>
                
            </div>
           
            <div class="columnLateral">
               <div id="joy1Div" style="width:200px;height:200px;margin:10px"></div>
                <div id="joy1Info">
                    <span>前后: <span id="joy1YValue">0</span></span>
                     <br>
                    <span>左右: <span id="joy1XValue">0</span></span>
                </div>
            </div>
        </div>


        <div class="buttons">
            <button class="btn" id="jump">Jump</button>
        </div>
    </center>
    
    <script>
        var socket; // socket通信
        var isConnected = false; // 连接状态

        var g_roll = 0; 
        var g_h = 30; 
        var g_stable = 0; 
        var joyX = 0;
        var joyY = 0;

        // 更新连接状态显示
        function updateConnectionStatus(connected) {
            isConnected = connected;
            const statusElement = document.getElementById('connectionStatus');
            if (connected) {
                statusElement.textContent = '已连接';
                statusElement.className = 'connection-status status-connected';
            } else {
                statusElement.textContent = '未连接';
                statusElement.className = 'connection-status status-disconnected';
            }
        }

        function socket_init() {
            try {
                // 根据环境选择合适的连接方式
                const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
                socket = new WebSocket(wsProtocol + '//' + window.location.hostname + ':81/');
                
                // 连接成功事件
                socket.onopen = function() {
                    // console.log('WebSocket连接已建立');
                    updateConnectionStatus(true);
                };
                
                // 接收消息事件
                socket.onmessage = function(event) {
                    console.log('收到消息:', event.data);
                    // 可以在这里处理从服务器返回的消息
                };
                
                // 连接关闭事件
                socket.onclose = function() {
                    console.log('WebSocket连接已关闭');
                    updateConnectionStatus(false);
                    // 尝试重连
                    setTimeout(socket_init, 3000);
                };
                
                // 错误事件
                socket.onerror = function(error) {
                    console.error('WebSocket错误:', error);
                    updateConnectionStatus(false);
                };
            } catch (e) {
                console.error('WebSocket初始化失败:', e);
                updateConnectionStatus(false);
                // 重试连接
                setTimeout(socket_init, 3000);
            }
        }

        function send_data() {
            var data = {
                'roll': g_roll,
                'height': g_h,
                'stable': g_stable,
                'mode': 'basic',
                'dir': "stop",
                'joy_y': joyY,
                'joy_x': joyX,
    
            };
            // console.log(data);
            socket.send(JSON.stringify(data));
        }

        function is_stable() {
            var obj = document.getElementById("stable");
            if(obj.checked) {
                // alert("is_stable checked");
                g_stable = 1;
            } else {
                // alert("is_stable unchecked");
                g_stable = 0;
            }
            send_data();
        }

        // 绑定按钮
        var buttons = document.getElementsByClassName("btn");
        for(i=0;i<buttons.length;i++) {
            buttons[i].addEventListener("mousedown",btn_down,true);
            buttons[i].addEventListener("mouseup",btn_up,true);
            buttons[i].addEventListener("touchstart",btn_down,true);
            buttons[i].addEventListener("touchend",btn_up,true);
        }

        function btn_down() {
            this.style = "background-color: cornflowerblue; color: white;";
            dir = (this.id == 'jump') ? 'jump' : 'stop';
            var data = {
                'dir': this.id,
                'mode': 'basic',
                'roll': g_roll,
                'height': g_h,
                'stable': g_stable,
                'joy_x': joyX,
                'joy_y': joyY,
            };
            // console.log(data);
            socket.send(JSON.stringify(data));
           
        }

        function btn_up() {
            this.style = "background-color: white; color: cornflowerblue;";

            dir = (this.id == 'jump') ? 'stop' : 'jump';
            var data = {
                'dir': "stop",
                'mode': 'basic',
                'roll': g_roll,
                'height': g_h,
                'stable': g_stable,
                'joy_x': joyX,
                'joy_y': joyY,
            };
            // console.log(data); // 打印测试
            socket.send(JSON.stringify(data));
           
        }

        /*摇杆内容*/
        var JoyStick = (function(container, parameters) {
            parameters = parameters || {};
            var title = (typeof parameters.title === "undefined" ? "joystick" : parameters.title),
                width = (typeof parameters.width === "undefined" ? 0 : parameters.width),
                height = (typeof parameters.height === "undefined" ? 0 : parameters.height),
                internalFillColor = (typeof parameters.internalFillColor === "undefined" ? "#4a90e2" : parameters.internalFillColor),
                internalLineWidth = (typeof parameters.internalLineWidth === "undefined" ? 2 : parameters.internalLineWidth),
                internalStrokeColor = (typeof parameters.internalStrokeColor === "undefined" ? "#4a90e2" : parameters.internalStrokeColor),
                externalLineWidth = (typeof parameters.externalLineWidth === "undefined" ? 2 : parameters.externalLineWidth),
                externalStrokeColor = (typeof parameters.externalStrokeColor ===  "undefined" ? "#4a90e2" : parameters.externalStrokeColor),
                autoReturnToCenter = (typeof parameters.autoReturnToCenter === "undefined" ? true : parameters.autoReturnToCenter);
            
            // Create Canvas element and add it in the Container object
            var objContainer = document.getElementById(container);
            var canvas = document.createElement("canvas");
            canvas.id = title;
            if(width === 0) { width = objContainer.clientWidth; }
            if(height === 0) { height = objContainer.clientHeight; }
            canvas.width = width;
            canvas.height = height;
            objContainer.appendChild(canvas);
            var context = canvas.getContext("2d");
            
            var isPressing = 0;
            var isMoving = 0;
            var isRelease = 0;
            
            var circumference = 2 * Math.PI;
            var internalRadius = (canvas.width - ((canvas.width / 2) + 10)) / 2;
            var maxMoveStick = internalRadius + 5;
            var externalRadius = internalRadius + 30;
            var centerX = canvas.width / 2;
            var centerY = canvas.height / 2;
            var directionHorizontalLimitPos = canvas.width / 10;
            var directionHorizontalLimitNeg = directionHorizontalLimitPos * -1;
            var directionVerticalLimitPos = canvas.height / 10;
            var directionVerticalLimitNeg = directionVerticalLimitPos * -1;
            // Used to save current position of stick
            var movedX = centerX;
            var movedY = centerY;
            
            // Check if the device support the touch or not
            if("ontouchstart" in document.documentElement) {
                canvas.addEventListener("touchstart", onTouchStart, true);
                canvas.addEventListener("touchmove", onTouchMove, true);
                document.addEventListener("touchend", onTouchEnd, true);
            } else {
                canvas.addEventListener("mousedown", onMouseDown, true);
                canvas.addEventListener("mousemove", onMouseMove, true);
                document.addEventListener("mouseup", onMouseUp, true);
            }
            // Draw the object
            drawExternal();
            drawInternal();

            /**
             * @desc Draw the external circle used as reference position
             */
            function drawExternal() {
                context.beginPath();
                context.arc(centerX, centerY, externalRadius, 0, circumference, false);
                context.lineWidth = externalLineWidth;
                context.strokeStyle = externalStrokeColor;
                context.stroke();
            }

            /**
             * @desc Draw the internal stick in the current position the user have moved it
             */
            function drawInternal() {
                context.beginPath();
                if(movedX < internalRadius) { movedX = maxMoveStick; }
                if((movedX + internalRadius) > canvas.width) { movedX = canvas.width - (maxMoveStick); }
                if(movedY < internalRadius) { movedY = maxMoveStick; }
                if((movedY + internalRadius) > canvas.height) { movedY = canvas.height - (maxMoveStick); }
                context.arc(movedX, movedY, internalRadius, 0, circumference, false);
                // create radial gradient
                var grd = context.createRadialGradient(centerX, centerY, 5, centerX, centerY, 200);
                // Light color
                grd.addColorStop(0, internalFillColor);
                // Dark color
                grd.addColorStop(1, internalStrokeColor);
                context.fillStyle = grd;
                context.fill();
                context.lineWidth = internalLineWidth;
                context.strokeStyle = internalStrokeColor;
                context.stroke();
            }

            function postCoordinate(containerId) {
                var xValue = (100 * ((movedX - centerX) / maxMoveStick)).toFixed();
                var yValue = ((100 * ((movedY - centerY) / maxMoveStick)) * -1).toFixed();

                if(containerId === 'joy1Div') {
                    joyX = xValue;
                    joyY = yValue;
                    // 更新 joy1 的显示信息
                    document.getElementById('joy1XValue').textContent = xValue;
                    document.getElementById('joy1YValue').textContent = yValue;
                } else if(containerId === 'joy2Div') {
                    // 限定 x 轴 roll 取值范围
                    let rollValue = parseInt((xValue * 30 / 100).toFixed());
                    if (rollValue < -30) {
                        rollValue = -30;
                    } else if (rollValue > 30) {
                        rollValue = 30;
                    }
                    g_roll = rollValue;

                    // 限定 y 轴 小车高度 取值范围为 15 到 85
                    let heightValue = parseInt(yValue) ;
                    if (heightValue < 0) {
                        heightValue = 0;
                    } else if (heightValue > 60) {
                        heightValue = 60;
                    }
                    g_h = heightValue;

                    // 更新 joy2 的显示信息，显示实际限制后的值
                    document.getElementById('joy2XValue').textContent = g_roll;
                    document.getElementById('joy2YValue').textContent = g_h;
                }

                send_data();
            }

            function releaseControl() {
                joyX = 0;
                joyY = 0;
                g_roll = 0;
                g_h = 30;
                // 重置显示信息
                document.getElementById('joy1XValue').textContent = '0';
                document.getElementById('joy1YValue').textContent = '0';
                document.getElementById('joy2XValue').textContent = '0';
                document.getElementById('joy2YValue').textContent = g_h;
                
                send_data();
            }  

            /**
             * @desc Events for manage touch
             */
            function noTouch(event) {
                isPressing = 0;
                isMoving = 0;
                isRelease = 0;
            }

            function onTouchStart(event) {
                isPressing = 1;
                isMoving = 0;
                isRelease = 0;
            }

            function onTouchMove(event) {
                // Prevent the browser from doing its default thing (scroll, zoom)
                event.preventDefault();
                if(isPressing === 1 && event.targetTouches[0].target === canvas) {
                    isMoving = 1;
                    isRelease = 0;
                    
                    movedX = event.targetTouches[0].pageX;
                    movedY = event.targetTouches[0].pageY;
                    // Manage offset
                    if(canvas.offsetParent.tagName.toUpperCase() === "BODY") {
                        movedX -= canvas.offsetLeft;
                        movedY -= canvas.offsetTop;
                    } else {
                        movedX -= canvas.offsetParent.offsetLeft;
                        movedY -= canvas.offsetParent.offsetTop;
                    }
                    // Delete canvas
                    context.clearRect(0, 0, canvas.width, canvas.height);
                    // Redraw object
                    drawExternal();
                    drawInternal();
                    
                    postCoordinate(canvas.parentNode.id);
                }
            } 

            function onTouchEnd(event) {
                //event.preventDefault();
                isPressing = 0;
                isMoving = 0;
                isRelease = 1;
                
                // If required reset position store variable
                if(autoReturnToCenter) {
                    movedX = centerX;
                    movedY = centerY;
                }
                // Delete canvas
                context.clearRect(0, 0, canvas.width, canvas.height);
                // Redraw object
                drawExternal();
                drawInternal();
                
                releaseControl();
            }

            /**
             * @desc Events for manage mouse
             */
            function noMouse(event) {
                isPressing = 0;
                isMoving = 0;
                isRelease = 0;
            }

            function onMouseDown(event) {
                isPressing = 1;
                isMoving = 0;
                isRelease = 0;
            }

            function onMouseMove(event) {
                if(isPressing === 1) {
                    isMoving = 1;
                    isRelease = 0;
                    
                    movedX = event.pageX;
                    movedY = event.pageY;
                    // Manage offset
                    if(canvas.offsetParent.tagName.toUpperCase() === "BODY") {
                        movedX -= canvas.offsetLeft;
                        movedY -= canvas.offsetTop;
                    } else {
                        movedX -= canvas.offsetParent.offsetLeft;
                        movedY -= canvas.offsetParent.offsetTop;
                    }
                    // Delete canvas
                    context.clearRect(0, 0, canvas.width, canvas.height);
                    // Redraw object
                    drawExternal();
                    drawInternal();
                    
                    postCoordinate(canvas.parentNode.id);
                }
            }

            function onMouseUp(event) {
                isPressing = 0;
                isMoving = 0;
                isRelease = 1;
                
                // If required reset position store variable
                if(autoReturnToCenter) {
                    movedX = centerX;
                    movedY = centerY;
                }
                // Delete canvas
                context.clearRect(0, 0, canvas.width, canvas.height);
                // Redraw object
                drawExternal();
                drawInternal();
                
                releaseControl();
            }

            this.GetX = function () {
                return (100 * ((movedX - centerX) / maxMoveStick)).toFixed();
            };

            /**
             * @desc Normalizzed value of Y move of stick
             * @return Integer from -100 to +100
             */
            this.GetY = function () {
                return ((100 * ((movedY - centerY) / maxMoveStick)) * -1).toFixed();
            };
        });

        var joy1Param = { "title": "1" };  
        var Joy1 = new JoyStick('joy1Div', joy1Param);
        var joy2Param = { "title": "2" };  
        var Joy2 = new JoyStick('joy2Div', joy2Param);
    </script> 
</body>
</html>